package io.aicn.lowcode.generator;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.config.DataSourceConfig;
import com.baomidou.mybatisplus.generator.config.GlobalConfig;
import com.baomidou.mybatisplus.generator.config.PackageConfig;
import com.baomidou.mybatisplus.generator.config.StrategyConfig;
import com.baomidou.mybatisplus.generator.config.TemplateConfig;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import io.aicn.lowcode.generator.model.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.env.Environment;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class MybatisPlusCodeGenerator {
    
    private final DataSource dataSource;
    private final Environment environment;
    
    @Autowired
    private QOVOGenerator qovoGenerator;
    
    public MybatisPlusCodeGenerator(DataSource dataSource, Environment environment) {
        this.dataSource = dataSource;
        this.environment = environment;
    }
    
    private void initializeDefaultConfigs(GenerationRequest request) {
        if (request.getEntityConfig() == null) {
            EntityConfig entityConfig = new EntityConfig();
            entityConfig.setPackageName("entity");
            request.setEntityConfig(entityConfig);
        }
        
        if (request.getMapperConfig() == null) {
            MapperConfig mapperConfig = new MapperConfig();
            mapperConfig.setPackageName("mapper");
            request.setMapperConfig(mapperConfig);
        }
        
        if (request.getServiceConfig() == null) {
            ServiceConfig serviceConfig = new ServiceConfig();
            serviceConfig.setPackageName("service");
            request.setServiceConfig(serviceConfig);
        }
        
        if (request.getControllerConfig() == null) {
            ControllerConfig controllerConfig = new ControllerConfig();
            controllerConfig.setPackageName("controller");
            request.setControllerConfig(controllerConfig);
        }
        
        if (request.getQoConfig() == null) {
            QOConfig qoConfig = new QOConfig();
            qoConfig.setPackageName("qo");
            request.setQoConfig(qoConfig);
        }
        
        if (request.getVoConfig() == null) {
            VOConfig voConfig = new VOConfig();
            voConfig.setPackageName("vo");
            request.setVoConfig(voConfig);
        }
        
        if (request.getOutputConfig() == null) {
            OutputConfig outputConfig = new OutputConfig();
            outputConfig.setOutputDir("./generated");
            outputConfig.setAuthor("System");
            request.setOutputConfig(outputConfig);
        }
    }
    
    public GenerationResult generateCode(GenerationRequest request) {
        try {
            // 0. 初始化默认配置
            initializeDefaultConfigs(request);
            
            // 1. 获取表信息
            io.aicn.lowcode.generator.model.TableInfo tableInfo = getTableInfo(request.getTableName());
            
            // 2. 配置代码生成器 - 使用硬编码配置确保密码正确
        DataSourceConfig dataSourceConfig = new DataSourceConfig.Builder(
                "jdbc:mysql://rm-bp1o5hmmwpdx0t5i92o.mysql.rds.aliyuncs.com:3306/lowcode?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC",
                "barry",
                "barry2025@"
        ).build();
            
            AutoGenerator generator = new AutoGenerator(dataSourceConfig);
            
            // 3. 全局配置
            GlobalConfig globalConfig = new GlobalConfig.Builder()
                    .outputDir(request.getOutputConfig().getOutputDir())
                    .author(request.getOutputConfig().getAuthor())
                    .dateType(DateType.TIME_PACK)
                    .build();
            
            generator.global(globalConfig);
            
            // 4. 包配置
            PackageConfig packageConfig = new PackageConfig.Builder()
                    .parent(request.getBasePackage())
                    .entity(request.getEntityConfig().getPackageName())
                    .mapper(request.getMapperConfig().getPackageName())
                    .service(request.getServiceConfig().getPackageName())
                    .controller(request.getControllerConfig().getPackageName())
                    .build();
            
            generator.packageInfo(packageConfig);
            
            // 5. 策略配置
            StrategyConfig.Builder strategyBuilder = new StrategyConfig.Builder()
                    .addInclude(request.getTableName());
            
            // 只有当tablePrefix不为null时才添加前缀
            if (request.getTablePrefix() != null && !request.getTablePrefix().trim().isEmpty()) {
                strategyBuilder.addTablePrefix(request.getTablePrefix().split(","));
            }
            
            StrategyConfig strategyConfig = strategyBuilder
                    .entityBuilder()
                    .naming(NamingStrategy.underline_to_camel)
                    .columnNaming(NamingStrategy.underline_to_camel)
                    .idType(IdType.AUTO)
                    .formatFileName("%s")
                    .mapperBuilder()
                    .enableBaseResultMap()
                    .enableBaseColumnList()
                    .formatMapperFileName("%sMapper")
                    .formatXmlFileName("%sMapper")
                    .serviceBuilder()
                    .formatServiceFileName("%sService")
                    .formatServiceImplFileName("%sServiceImpl")
                    .controllerBuilder()
                    .enableRestStyle()
                    .formatFileName("%sController")
                    .build();
            
            generator.strategy(strategyConfig);
            
            // 6. 执行生成
            generator.execute(new FreemarkerTemplateEngine());
            
            // 7. 生成QO和VO类
            if (request.isGenerateQO() || request.isGenerateVO()) {
                generateQOVO(request, tableInfo);
            }
            
            return new GenerationResult(true, "代码生成成功", getGeneratedFiles(request));
            
        } catch (Exception e) {
            e.printStackTrace();
            String errorMessage = e.getMessage() != null ? e.getMessage() : e.getClass().getSimpleName();
            return new GenerationResult(false, "代码生成失败: " + errorMessage, null);
        }
    }
    
    public io.aicn.lowcode.generator.model.TableInfo getTableInfo(String tableName) throws Exception {
        io.aicn.lowcode.generator.model.TableInfo tableInfo = new io.aicn.lowcode.generator.model.TableInfo();
        tableInfo.setTableName(tableName);
        
        try (Connection connection = dataSource.getConnection()) {
            DatabaseMetaData metaData = connection.getMetaData();
            
            // 获取表信息
            try (ResultSet rs = metaData.getTables(null, null, tableName, new String[]{"TABLE"})) {
                if (rs.next()) {
                    tableInfo.setTableComment(rs.getString("REMARKS"));
                }
            }
            
            // 获取列信息
            List<ColumnInfo> columns = new ArrayList<>();
            try (ResultSet rs = metaData.getColumns(null, null, tableName, null)) {
                while (rs.next()) {
                    ColumnInfo column = new ColumnInfo();
                    column.setName(rs.getString("COLUMN_NAME"));
                    column.setType(rs.getString("TYPE_NAME"));
                    column.setLength(rs.getInt("COLUMN_SIZE"));
                    column.setNullable(rs.getInt("NULLABLE") == 1);
                    column.setDefaultValue(rs.getString("COLUMN_DEF"));
                    column.setComment(rs.getString("REMARKS"));
                    column.setAutoIncrement("YES".equals(rs.getString("IS_AUTOINCREMENT")));
                    
                    // 设置Java类型
                    column.setJavaType(getJavaType(column.getType()));
                    column.setJavaProperty(underscoreToCamel(column.getName()));
                    
                    columns.add(column);
                }
            }
            
            // 获取主键信息
            try (ResultSet rs = metaData.getPrimaryKeys(null, null, tableName)) {
                while (rs.next()) {
                    String pkColumnName = rs.getString("COLUMN_NAME");
                    columns.stream()
                            .filter(col -> col.getName().equals(pkColumnName))
                            .forEach(col -> col.setPrimaryKey(true));
                }
            }
            
            tableInfo.setColumns(columns);
        }
        
        return tableInfo;
    }
    
    private String getJavaType(String sqlType) {
        if (sqlType == null) return "Object";
        
        sqlType = sqlType.toUpperCase();
        
        // 基础数值类型
        if (sqlType.contains("TINYINT")) {
            return "Byte";
        } else if (sqlType.contains("SMALLINT")) {
            return "Short";
        } else if (sqlType.contains("INT") || sqlType.contains("INTEGER")) {
            return "Integer";
        } else if (sqlType.contains("BIGINT")) {
            return "Long";
        } else if (sqlType.contains("FLOAT")) {
            return "Float";
        } else if (sqlType.contains("REAL") || sqlType.contains("DOUBLE")) {
            return "Double";
        } else if (sqlType.contains("DECIMAL") || sqlType.contains("NUMERIC")) {
            return "BigDecimal";
        }
        // 日期时间类型
        else if (sqlType.contains("DATE") && !sqlType.contains("TIME")) {
            return "LocalDate";
        } else if (sqlType.contains("TIME") && !sqlType.contains("STAMP")) {
            return "LocalTime";
        } else if (sqlType.contains("DATETIME")) {
            return "LocalDateTime";
        } else if (sqlType.contains("TIMESTAMP")) {
            return "LocalDateTime";
        } else if (sqlType.contains("YEAR")) {
            return "Year";
        }
        // 字符串类型
        else if (sqlType.contains("CHAR") || sqlType.contains("VARCHAR")) {
            return "String";
        } else if (sqlType.contains("TEXT") || sqlType.contains("CLOB")) {
            return "String";
        }
        // 二进制类型
        else if (sqlType.contains("BLOB") || sqlType.contains("BINARY")) {
            return "byte[]";
        }
        // 布尔类型
        else if (sqlType.contains("BOOLEAN") || sqlType.contains("BIT")) {
            return "Boolean";
        }
        // JSON类型
        else if (sqlType.contains("JSON")) {
            return "String";
        }
        // 枚举类型
        else if (sqlType.contains("ENUM")) {
            return "String";
        }
        // 集合类型
        else if (sqlType.contains("SET")) {
            return "String";
        }
        // 默认类型
        else {
            return "String";
        }
    }
    
    private String underscoreToCamel(String input) {
        if (input == null || input.isEmpty()) {
            return input;
        }
        
        StringBuilder result = new StringBuilder();
        boolean nextUpper = false;
        
        for (int i = 0; i < input.length(); i++) {
            char currentChar = input.charAt(i);
            if (currentChar == '_') {
                nextUpper = true;
            } else {
                if (nextUpper) {
                    result.append(Character.toUpperCase(currentChar));
                    nextUpper = false;
                } else {
                    result.append(Character.toLowerCase(currentChar));
                }
            }
        }
        
        return result.toString();
    }
    
    public List<String> getTableList() {
        List<String> tables = new ArrayList<>();
        try (Connection connection = dataSource.getConnection()) {
            DatabaseMetaData metaData = connection.getMetaData();
            try (ResultSet rs = metaData.getTables(null, null, "%", new String[]{"TABLE"})) {
                while (rs.next()) {
                    tables.add(rs.getString("TABLE_NAME"));
                }
            }
        } catch (Exception e) {
            throw new RuntimeException("获取表列表失败: " + e.getMessage());
        }
        return tables;
    }
    
    private List<String> getGeneratedFiles(GenerationRequest request) {
        List<String> files = new ArrayList<>();
        String baseDir = request.getOutputConfig().getOutputDir();
        String basePackage = request.getBasePackage().replace(".", "/");
        
        // Entity文件
        files.add(baseDir + "/java/" + basePackage + "/entity/" + request.getEntityConfig().getClassName() + ".java");
        
        // Mapper文件
        files.add(baseDir + "/java/" + basePackage + "/mapper/" + request.getMapperConfig().getClassName() + ".java");
        files.add(baseDir + "/resources/mapper/" + request.getMapperConfig().getClassName() + ".xml");
        
        // Service文件
        if (request.getServiceConfig().isInterfaceEnabled()) {
            files.add(baseDir + "/java/" + basePackage + "/service/" + request.getServiceConfig().getInterfaceName() + ".java");
        }
        files.add(baseDir + "/java/" + basePackage + "/service/impl/" + request.getServiceConfig().getClassName() + ".java");
        
        // Controller文件
        files.add(baseDir + "/java/" + basePackage + "/controller/" + request.getControllerConfig().getClassName() + ".java");
        
        
        // QO文件
        if (request.isGenerateQO() && request.getQoConfig() != null) {
            String qoClassName = request.getQoConfig().getClassName();
            if (qoClassName == null) {
                qoClassName = toPascalCase(request.getTableName()) + "QO";
            }
            String qoPackage = request.getQoConfig().getPackageName().replace(".", "/");
            files.add(baseDir + "/java/" + qoPackage + "/" + qoClassName + ".java");
        }
        
        // VO文件
        if (request.isGenerateVO() && request.getVoConfig() != null) {
            String voClassName = request.getVoConfig().getClassName();
            if (voClassName == null) {
                voClassName = toPascalCase(request.getTableName()) + "VO";
            }
            String voPackage = request.getVoConfig().getPackageName().replace(".", "/");
            files.add(baseDir + "/java/" + voPackage + "/" + voClassName + ".java");
        }
        
        return files;
    }
    
    private void generateQOVO(GenerationRequest request, io.aicn.lowcode.generator.model.TableInfo tableInfo) {
        try {
            if (request.isGenerateQO()) {
                qovoGenerator.generateQO(request, tableInfo);
            }
            if (request.isGenerateVO()) {
                qovoGenerator.generateVO(request, tableInfo);
            }
            
            // 如果生成了QO或VO，重新生成使用QO/VO的Controller
            if (request.isGenerateQO() || request.isGenerateVO()) {
                generateControllerWithQOVO(request, tableInfo);
            }
        } catch (Exception e) {
            throw new RuntimeException("生成QO/VO类失败: " + e.getMessage(), e);
        }
    }
    
    private void generateControllerWithQOVO(GenerationRequest request, io.aicn.lowcode.generator.model.TableInfo tableInfo) {
        try {
            // 创建自定义模板引擎配置
            TemplateConfig templateConfig = new TemplateConfig.Builder()
                    .controller("/templates/controller_qovo.java")
                    .build();
            
            // 数据源配置
            DataSourceConfig dataSourceConfig = new DataSourceConfig.Builder(
                    "jdbc:mysql://rm-bp1o5hmmwpdx0t5i92o.mysql.rds.aliyuncs.com:3306/lowcode?useUnicode=true&characterEncoding=UTF-8&useSSL=true&serverTimezone=UTC",
                    "barry",
                    "barry2025@"
            ).build();
            
            // 创建代码生成器
            AutoGenerator generator = new AutoGenerator(dataSourceConfig);
            
            // 全局配置
            GlobalConfig globalConfig = new GlobalConfig.Builder()
                    .outputDir(request.getOutputConfig().getOutputDir() + "/java")
                    .author(request.getOutputConfig().getAuthor())
                    .enableSwagger()
                    .disableOpenDir()
                    .build();
            
            // 包配置
            PackageConfig packageConfig = new PackageConfig.Builder()
                    .parent(request.getBasePackage())
                    .entity("entity")
                    .mapper("mapper")
                    .service("service")
                    .serviceImpl("service.impl")
                    .controller("controller")
                    .build();
            
            // 策略配置
            StrategyConfig strategyConfig = new StrategyConfig.Builder()
                    .addInclude(tableInfo.getTableName())
                    .entityBuilder()
                    .enableLombok()
                    .enableTableFieldAnnotation()
                    .controllerBuilder()
                    .enableRestStyle()
                    .formatFileName("%sController")
                    .build();
            
            generator.global(globalConfig)
                    .packageInfo(packageConfig)
                    .template(templateConfig)
                    .strategy(strategyConfig);
            
            // 创建自定义模板引擎，传递QO/VO配置
            FreemarkerTemplateEngine templateEngine = new FreemarkerTemplateEngine() {
                @Override
                protected void outputController(com.baomidou.mybatisplus.generator.config.po.TableInfo tableInfo, Map<String, Object> objectMap) {
                    // 添加QO和VO配置到模板变量
                    if (request.isGenerateQO()) {
                        Map<String, Object> qoConfig = new HashMap<>();
                        qoConfig.put("className", toPascalCase(tableInfo.getName()) + "QO");
                        qoConfig.put("packageName", request.getBasePackage() + ".qo");
                        objectMap.put("qoConfig", qoConfig);
                    }
                    
                    if (request.isGenerateVO()) {
                        Map<String, Object> voConfig = new HashMap<>();
                        voConfig.put("className", toPascalCase(tableInfo.getName()) + "VO");
                        voConfig.put("packageName", request.getBasePackage() + ".vo");
                        objectMap.put("voConfig", voConfig);
                    }
                    
                    super.outputController(tableInfo, objectMap);
                }
            };
            
            // 执行生成
            generator.execute(templateEngine);
            
        } catch (Exception e) {
            throw new RuntimeException("生成Controller失败: " + e.getMessage(), e);
        }
    }
    
    private String toPascalCase(String input) {
        if (input == null || input.isEmpty()) {
            return input;
        }
        
        StringBuilder result = new StringBuilder();
        boolean nextUpper = true;
        
        for (int i = 0; i < input.length(); i++) {
            char currentChar = input.charAt(i);
            if (currentChar == '_') {
                nextUpper = true;
            } else {
                if (nextUpper) {
                    result.append(Character.toUpperCase(currentChar));
                    nextUpper = false;
                } else {
                    result.append(Character.toLowerCase(currentChar));
                }
            }
        }
        
        return result.toString();
    }
}